//
//  NSString+QTAdd.m
//  Pods
//
//  Created by 张俊博 on 16/8/22.
//
//

#import "NSString+QTAdd.h"
#import "NSData+QTAdd.h"
#import "NSNumber+QTAdd.h"
#import "UIDevice+QTAdd.h"
#import "QTCategoryMacro.h"
#import <CommonCrypto/CommonHMAC.h>
#import <CoreText/CoreText.h>

QTSYNTH_DUMMY_CLASS(NSString_QTAdd)

@implementation NSString (QTAdd)

- (NSString *)md2String {
    return [[self dataUsingEncoding:NSUTF8StringEncoding] md2String];
}

- (NSString *)md4String {
    return [[self dataUsingEncoding:NSUTF8StringEncoding] md4String];
}

- (NSString *)md5String {
    return [[self dataUsingEncoding:NSUTF8StringEncoding] md5String];
}

- (NSString *)sha1String {
    return [[self dataUsingEncoding:NSUTF8StringEncoding] sha1String];
}

- (NSString *)sha224String {
    return [[self dataUsingEncoding:NSUTF8StringEncoding] sha224String];
}

- (NSString *)sha256String {
    return [[self dataUsingEncoding:NSUTF8StringEncoding] sha256String];
}

- (NSString *)sha384String {
    return [[self dataUsingEncoding:NSUTF8StringEncoding] sha384String];
}

- (NSString *)sha512String {
    return [[self dataUsingEncoding:NSUTF8StringEncoding] sha512String];
}

- (NSString *)crc32String {
    return [[self dataUsingEncoding:NSUTF8StringEncoding] crc32String];
}

- (NSString *)hmacMD5StringWithKey:(NSString *)key {
    return [[self dataUsingEncoding:NSUTF8StringEncoding]
            hmacMD5StringWithKey:key];
}

- (NSString *)hmacSHA1StringWithKey:(NSString *)key {
    return [[self dataUsingEncoding:NSUTF8StringEncoding]
            hmacSHA1StringWithKey:key];
}

- (NSString *)hmacSHA224StringWithKey:(NSString *)key {
    return [[self dataUsingEncoding:NSUTF8StringEncoding]
            hmacSHA224StringWithKey:key];
}

- (NSString *)hmacSHA256StringWithKey:(NSString *)key {
    return [[self dataUsingEncoding:NSUTF8StringEncoding]
            hmacSHA256StringWithKey:key];
}

- (NSString *)hmacSHA384StringWithKey:(NSString *)key {
    return [[self dataUsingEncoding:NSUTF8StringEncoding]
            hmacSHA384StringWithKey:key];
}

- (NSString *)hmacSHA512StringWithKey:(NSString *)key {
    return [[self dataUsingEncoding:NSUTF8StringEncoding]
            hmacSHA512StringWithKey:key];
}

- (NSString *)base64EncodedString {
    return [[self dataUsingEncoding:NSUTF8StringEncoding] base64EncodedString];
}

+ (NSString *)stringWithBase64EncodedString:(NSString *)base64EncodedString {
    NSData *data = [NSData dataWithBase64EncodedString:base64EncodedString];
    return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}

- (NSString *)stringByURLEncode {
    if ([self respondsToSelector:@selector(stringByAddingPercentEncodingWithAllowedCharacters:)]) {
        /**
         AFNetworking/AFURLRequestSerialization.m
         
         Returns a percent-escaped string following RFC 3986 for a query string key or value.
         RFC 3986 states that the following characters are "reserved" characters.
         - General Delimiters: ":", "#", "[", "]", "@", "?", "/"
         - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
         In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
         query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
         should be percent-escaped in the query string.
         - parameter string: The string to be percent-escaped.
         - returns: The percent-escaped string.
         */
        static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
        static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";
        
        NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
        [allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];
        static NSUInteger const batchSize = 50;
        
        NSUInteger index = 0;
        NSMutableString *escaped = @"".mutableCopy;
        
        while (index < self.length) {
            NSUInteger length = MIN(self.length - index, batchSize);
            NSRange range = NSMakeRange(index, length);
            // To avoid breaking up character sequences such as ����
            range = [self rangeOfComposedCharacterSequencesForRange:range];
            NSString *substring = [self substringWithRange:range];
            NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
            [escaped appendString:encoded];
            
            index += range.length;
        }
        return escaped;
    } else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        CFStringEncoding cfEncoding = CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding);
        NSString *encoded = (__bridge_transfer NSString *)
        CFURLCreateStringByAddingPercentEscapes(
                                                kCFAllocatorDefault,
                                                (__bridge CFStringRef)self,
                                                NULL,
                                                CFSTR("!#$&'()*+,/:;=?@[]"),
                                                cfEncoding);
        return encoded;
#pragma clang diagnostic pop
    }
}

- (NSString *)stringByRouterURLEncode
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    CFStringEncoding cfEncoding = CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding);
    NSString *encoded = (__bridge_transfer NSString *)
    CFURLCreateStringByAddingPercentEscapes(
                                            kCFAllocatorDefault,
                                            (__bridge CFStringRef)self,
                                            NULL,
                                            CFSTR("!#$&'()*+,/:;=?@[]"),
                                            cfEncoding);
    return encoded;
#pragma clang diagnostic pop
}

- (NSString *)stringByURLDecode {
    if ([self respondsToSelector:@selector(stringByRemovingPercentEncoding)]) {
        return [self stringByRemovingPercentEncoding];
    } else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        CFStringEncoding en = CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding);
        NSString *decoded = [self stringByReplacingOccurrencesOfString:@"+"
                                                            withString:@" "];
        decoded = (__bridge_transfer NSString *)
        CFURLCreateStringByReplacingPercentEscapesUsingEncoding(
                                                                NULL,
                                                                (__bridge CFStringRef)decoded,
                                                                CFSTR(""),
                                                                en);
        return decoded;
#pragma clang diagnostic pop
    }
}

- (NSString *)stringByEscapingHTML {
    NSUInteger len = self.length;
    if (!len) return self;
    
    unichar *buf = malloc(sizeof(unichar) * len);
    if (!buf) return self;
    [self getCharacters:buf range:NSMakeRange(0, len)];
    
    NSMutableString *result = [NSMutableString string];
    for (int i = 0; i < len; i++) {
        unichar c = buf[i];
        NSString *esc = nil;
        switch (c) {
            case 34: esc = @"&quot;"; break;
            case 38: esc = @"&amp;"; break;
            case 39: esc = @"&apos;"; break;
            case 60: esc = @"&lt;"; break;
            case 62: esc = @"&gt;"; break;
            default: break;
        }
        if (esc) {
            [result appendString:esc];
        } else {
            CFStringAppendCharacters((CFMutableStringRef)result, &c, 1);
        }
    }
    free(buf);
    return result;
}

- (CGSize)sizeForFont:(UIFont *)font size:(CGSize)size mode:(NSLineBreakMode)lineBreakMode {
    CGSize result;
    if (!font) font = [UIFont systemFontOfSize:12];
    if ([self containEmoji]) {
        NSMutableDictionary *attr = [NSMutableDictionary new];
        attr[NSFontAttributeName] = font;
        if (lineBreakMode != NSLineBreakByWordWrapping) {
            NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
            paragraphStyle.lineBreakMode = lineBreakMode;
            attr[NSParagraphStyleAttributeName] = paragraphStyle;
        }
        NSAttributedString *attrStr = [[NSAttributedString alloc] initWithString:self attributes:attr];
        CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attrStr);
        result= CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, (CFIndex)[self length]), NULL, size, NULL);
        if(framesetter) CFRelease(framesetter);
    } else if ([self respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) {
        NSMutableDictionary *attr = [NSMutableDictionary new];
        attr[NSFontAttributeName] = font;
        if (lineBreakMode != NSLineBreakByWordWrapping) {
            NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
            paragraphStyle.lineBreakMode = lineBreakMode;
            attr[NSParagraphStyleAttributeName] = paragraphStyle;
        }
        CGRect rect = [self boundingRectWithSize:size
                                         options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
                                      attributes:attr context:nil];
        result = rect.size;
    } else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        result = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode];
#pragma clang diagnostic pop
    }
    return CGSizeMake(ceilf(result.width), ceilf(result.height));
}

- (CGFloat)widthForFont:(UIFont *)font {
    CGSize size = [self sizeForFont:font size:CGSizeMake(HUGE, HUGE) mode:NSLineBreakByWordWrapping];
    return size.width;
}

- (CGFloat)heightForFont:(UIFont *)font width:(CGFloat)width {
    CGSize size = [self sizeForFont:font size:CGSizeMake(width, HUGE) mode:NSLineBreakByWordWrapping];
    return size.height;
}

- (BOOL)matchesRegex:(NSString *)regex options:(NSRegularExpressionOptions)options {
    NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:NULL];
    if (!pattern) return NO;
    return ([pattern numberOfMatchesInString:self options:0 range:NSMakeRange(0, self.length)] > 0);
}

- (void)enumerateRegexMatches:(NSString *)regex
                      options:(NSRegularExpressionOptions)options
                   usingBlock:(void (^)(NSString *match, NSRange matchRange, BOOL *stop))block {
    if (regex.length == 0 || !block) return;
    NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:nil];
    if (!regex) return;
    [pattern enumerateMatchesInString:self options:kNilOptions range:NSMakeRange(0, self.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
        block([self substringWithRange:result.range], result.range, stop);
    }];
}

- (NSString *)stringByReplacingRegex:(NSString *)regex
                             options:(NSRegularExpressionOptions)options
                          withString:(NSString *)replacement; {
    NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:regex options:options error:nil];
    if (!pattern) return self;
    return [pattern stringByReplacingMatchesInString:self options:0 range:NSMakeRange(0, [self length]) withTemplate:replacement];
}

- (char)charValue {
    return self.numberValue.charValue;
}

- (unsigned char) unsignedCharValue {
    return self.numberValue.unsignedCharValue;
}

- (short) shortValue {
    return self.numberValue.shortValue;
}

- (unsigned short) unsignedShortValue {
    return self.numberValue.unsignedShortValue;
}

- (unsigned int) unsignedIntValue {
    return self.numberValue.unsignedIntValue;
}

- (long) longValue {
    return self.numberValue.longValue;
}

- (unsigned long) unsignedLongValue {
    return self.numberValue.unsignedLongValue;
}

- (unsigned long long) unsignedLongLongValue {
    return self.numberValue.unsignedLongLongValue;
}

- (NSUInteger) unsignedIntegerValue {
    return self.numberValue.unsignedIntegerValue;
}


+ (NSString *)stringWithUUID {
    CFUUIDRef uuid = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, uuid);
    if(uuid) CFRelease(uuid);
    return (__bridge_transfer NSString *)string;
}

+ (NSString *)stringWithUTF32Char:(UTF32Char)char32 {
    char32 = NSSwapHostIntToLittle(char32);
    return [[NSString alloc] initWithBytes:&char32 length:4 encoding:NSUTF32LittleEndianStringEncoding];
}

+ (NSString *)stringWithUTF32Chars:(const UTF32Char *)char32 length:(NSUInteger)length {
    return [[NSString alloc] initWithBytes:(const void *)char32
                                    length:length * 4
                                  encoding:NSUTF32LittleEndianStringEncoding];
}

- (void)enumerateUTF32CharInRange:(NSRange)range usingBlock:(void (^)(UTF32Char char32, NSRange range, BOOL *stop))block {
    NSString *str = self;
    if (range.location != 0 || range.length != self.length) {
        str = [self substringWithRange:range];
    }
    NSUInteger len = [str lengthOfBytesUsingEncoding:NSUTF32StringEncoding] / 4;
    UTF32Char *char32 = (UTF32Char *)[str cStringUsingEncoding:NSUTF32LittleEndianStringEncoding];
    if (len == 0 || char32 == NULL) return;
    
    NSUInteger location = 0;
    BOOL stop = NO;
    NSRange subRange;
    UTF32Char oneChar;
    
    for (NSUInteger i = 0; i < len; i++) {
        oneChar = char32[i];
        subRange = NSMakeRange(location, oneChar > 0xFFFF ? 2 : 1);
        block(oneChar, subRange, &stop);
        if (stop) return;
        location += subRange.length;
    }
}

- (NSString *)stringByTrim {
    NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    return [self stringByTrimmingCharactersInSet:set];
}

- (NSString *)stringByAppendingNameScale:(CGFloat)scale {
    if (fabs(scale - 1) <= __FLT_EPSILON__ || self.length == 0 || [self hasSuffix:@"/"]) return self.copy;
    return [self stringByAppendingFormat:@"@%@x", @(scale)];
}

- (NSString *)stringByAppendingPathScale:(CGFloat)scale {
    if (fabs(scale - 1) <= __FLT_EPSILON__ || self.length == 0 || [self hasSuffix:@"/"]) return self.copy;
    NSString *ext = self.pathExtension;
    NSRange extRange = NSMakeRange(self.length - ext.length, 0);
    if (ext.length > 0) extRange.location -= 1;
    NSString *scaleStr = [NSString stringWithFormat:@"@%@x", @(scale)];
    return [self stringByReplacingCharactersInRange:extRange withString:scaleStr];
}

- (CGFloat)pathScale {
    if (self.length == 0 || [self hasSuffix:@"/"]) return 1;
    NSString *name = self.stringByDeletingPathExtension;
    __block CGFloat scale = 1;
    [name enumerateRegexMatches:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines usingBlock: ^(NSString *match, NSRange matchRange, BOOL *stop) {
        scale = [match substringWithRange:NSMakeRange(1, match.length - 2)].doubleValue;
    }];
    return scale;
}

- (BOOL)isNotBlank {
    NSCharacterSet *blank = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    for (NSInteger i = 0; i < self.length; ++i) {
        unichar c = [self characterAtIndex:i];
        if (![blank characterIsMember:c]) {
            return YES;
        }
    }
    return NO;
}

- (BOOL)containsString:(NSString *)string {
    if (string == nil) return NO;
    return [self rangeOfString:string].location != NSNotFound;
}

- (BOOL)containsCharacterSet:(NSCharacterSet *)set {
    if (set == nil) return NO;
    return [self rangeOfCharacterFromSet:set].location != NSNotFound;
}

- (NSNumber *)numberValue {
    return [NSNumber numberWithString:self];
}

- (NSData *)dataValue {
    return [self dataUsingEncoding:NSUTF8StringEncoding];
}

- (NSRange)rangeOfAll {
    return NSMakeRange(0, self.length);
}

- (id)jsonValueDecoded {
    return [[self dataValue] jsonValueDecoded];
}

+ (NSString *)stringNamed:(NSString *)name {
    NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@""];
    NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
    if (!str) {
        path = [[NSBundle mainBundle] pathForResource:name ofType:@"txt"];
        str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
    }
    return str;
}

- (BOOL)isTokenOverdue
{
    if (self.length<=0) {
        return YES;
    }
    
    NSArray *array = [self componentsSeparatedByString:@"."];
    if (array.count<3) {
        return YES;
    }
    
    NSMutableString *timestamp = [NSMutableString stringWithString:array[1]];
    
    //解码
    NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:timestamp options:0];
    NSInteger count = 0;
    while (!decodedData && count<2) {
        ++count;
        [timestamp appendString:@"="];
        decodedData = [[NSData alloc] initWithBase64EncodedString:timestamp
                                                          options:0];
    }
    if (!decodedData) {
        return YES;
    }
    
    //    NSString *decodeString = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
    
    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:decodedData options:0 error:nil];
    if (!json || !json[@"expires"]) {
        return YES;
    }
    
    NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
    NSTimeInterval old = [json[@"expires"] doubleValue];
    
    //提前一分钟
    return  now - 60 >= old;
}

- (NSString *)MD5Encode {
    unsigned char *digest = malloc(CC_MD5_DIGEST_LENGTH);
    CC_MD5(self.UTF8String, (CC_LONG)strlen(self.UTF8String), digest);
    NSMutableString *md5String = [NSMutableString string];
    for ( int i = 0 ; i < CC_MD5_DIGEST_LENGTH ; i++) {
        [md5String appendFormat : @"%02x" ,digest[i]];
    }
    
    return md5String;
}

-(NSString *)MD5EncodeWithDefaultSalt{
    NSString *defaultSalt = @"{7zs1JKiilF}";
    
    return  [self stringByAppendingString:defaultSalt].MD5Encode;
}

- (NSString *)MD5EncodeWithSalt:(NSString *)salt
{
    NSMutableString *firstEndoe = [NSMutableString stringWithString:self.MD5Encode];
    [firstEndoe appendString:salt];
    
    return firstEndoe.MD5Encode;
}

- (NSString *)transformToPinyin
{
    NSMutableString *mutableString = [NSMutableString stringWithString:self];
    
//    CFStringTransform((__bridge CFMutableStringRef)mutableString,
//                      NULL,
//                      kCFStringTransformToLatin,
//                      false);
//    CFStringTransform((__bridge CFMutableStringRef)mutableString,
//                      NULL,
//                      kCFStringTransformStripDiacritics,
//                      false);
    
    CFStringTransform((CFMutableStringRef)mutableString,
                      NULL,
                      kCFStringTransformToLatin,
                      false);
    
    mutableString = (NSMutableString *)[mutableString stringByFoldingWithOptions:NSDiacriticInsensitiveSearch
                                                                          locale:[NSLocale currentLocale]];
    
    
    return [mutableString stringByReplacingOccurrencesOfString:@" " withString:@""];
}

- (NSString *)firstLatter
{
    NSString *pinyin = [self transformToPinyin];
    if (pinyin && pinyin.length>0 && isalpha([pinyin characterAtIndex:0])) {
        return [[NSString stringWithFormat:@"%c", [pinyin characterAtIndex:0]] uppercaseString];
    } else {
        return @"#";
    }
}

- (NSString *)relativePath {
    if (![self containsString:NSHomeDirectory()]) {
        return self;
    } else {
        NSRange range = [self rangeOfString:NSHomeDirectory()];
        return [self stringByReplacingCharactersInRange:NSMakeRange(0, range.location+range.length) withString:@""];
//        return [self stringByReplacingOccurrencesOfString:NSHomeDirectory() withString:@""];
    }
}

- (NSString *)absolutePaths {
    if ([self containsString:NSHomeDirectory()]) {
        return self;
    } else {
        return [NSHomeDirectory() stringByAppendingString:self];
    }
}

- (BOOL)isNumber
{
    NSString *numberRegex = @"[0-9]*";
    NSPredicate *numberTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",numberRegex];
    return [numberTest evaluateWithObject:self];
}

- (BOOL)isAlpha
{
    NSString *alphaRegex = @"[a-zA-Z]*";
    NSPredicate *alphaTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",alphaRegex];
    return [alphaTest evaluateWithObject:self];
}

- (BOOL)isPhoneNumber
{
//    NSString *phoneRegex = @"^((13[0-9])|(14[0-9])|(15[^4,\\D])|(17[0,0-9])|(18[0,0-9]))\\d{8}$";
//    NSPredicate *phoneTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",phoneRegex];
//    return [phoneTest evaluateWithObject:self];
    
    return [self isPhoneNumberForCountry:CountryType_Zh]
            || [self isPhoneNumberForCountry:CountryType_Us]
            || [self isPhoneNumberForCountry:CountryType_En]
            || [self isPhoneNumberForCountry:CountryType_In];
}

- (BOOL)isPhoneNumberForCountry:(CountryType)country
{
    //中国
    BOOL (^isPhoneForZh)(void) = ^() {
        NSString *zhPhone = [self stringByReplacingOccurrencesOfString:@"+86" withString:@""];
        NSString *zhPhoneRegex = @"^((13[0-9])|(14[0-9])|(15[^4,\\D])|(17[0,0-9])|(18[0,0-9]))\\d{8}$";
        NSPredicate *zhPhoneTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",zhPhoneRegex];
        return [zhPhoneTest evaluateWithObject:zhPhone];
    };
    
    //英国 10位数字
    BOOL (^isPhoneForUK)(void) = ^() {
        NSString *ukPhone = [self stringByReplacingOccurrencesOfString:@"+44" withString:@""];
        NSString *ukPhoneRegex = @"^[0-9]{10}$";
        NSPredicate *ukPhoneTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",ukPhoneRegex];
        return [ukPhoneTest evaluateWithObject:ukPhone];
    };
    
    //美国 10位数字
    BOOL (^isPhoneForUs)(void) = ^() {
        NSString *usPhone = [self stringByReplacingOccurrencesOfString:@"+1" withString:@""];
        NSString *usPhoneRegex = @"^[0-9]{10}$";
        NSPredicate *usPhoneTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",usPhoneRegex];
        return [usPhoneTest evaluateWithObject:usPhone];
    };
    
    //印度 7-10位数字
    BOOL (^isPhoneForIn)(void) = ^() {
        NSString *inPhone = [self stringByReplacingOccurrencesOfString:@"+91" withString:@""];
        NSString *inPhoneRegex = @"^[0-9]{7,10}$";
        NSPredicate *inPhoneTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",inPhoneRegex];
        return [inPhoneTest evaluateWithObject:inPhone];
    };
    
    
    if ([self hasPrefix:@"+86"]) {
        return isPhoneForZh();
    } else if ([self hasPrefix:@"+44"]) {
        return isPhoneForUK();
    } else if ([self hasPrefix:@"+1"]) {
        return isPhoneForUs();
    } else if ([self hasPrefix:@"+91"]) {
        return isPhoneForIn();
    } else {
        switch (country) {
            case CountryType_Zh:
                return isPhoneForZh();
                break;
            case CountryType_Us:
                return isPhoneForUK();
                break;
            case CountryType_En:
                return isPhoneForUs();
                break;
            case CountryType_In:
                return isPhoneForIn();
                break;
                
            default:
                break;
        }
    }
    
    return NO;
}

- (NSString *)phoneNumberCountry:(CountryType)defaulCountry {
    if ([self hasPrefix:@"+86"]) {
        return @"+86";
    } else if ([self hasPrefix:@"+44"]) {
        return @"+44";
    } else if ([self hasPrefix:@"+91"]) {
        return @"+91";
    } else if ([self hasPrefix:@"+1"]) {
        return @"+1";
    } else {
        if (defaulCountry == CountryType_Zh) {
            return @"+86";
        } else if (defaulCountry == CountryType_En) {
            return @"+44";
        } else if (defaulCountry == CountryType_In) {
            return @"91";
        } else if (defaulCountry == CountryType_Us) {
            return @"+1";
        }
    }
    return @"+86";
}

- (NSString *)phoneNumberWithoutCountry {
    NSString *str = [self stringByReplacingOccurrencesOfString:@"+86" withString:@""];
    str = [str stringByReplacingOccurrencesOfString:@"+44" withString:@""];
    str = [str stringByReplacingOccurrencesOfString:@"+91" withString:@""];
    str = [str stringByReplacingOccurrencesOfString:@"+1" withString:@""];
    return str;
}

- (BOOL)isEmail
{
    NSString *emailRegex = @"[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
    NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex];
    return [emailTest evaluateWithObject:self];
}

- (BOOL)isDomainId
{
    //domainId由小写字母和数字组成，长度32位
    NSString *domainRegex = @"^[a-z0-9]{32}";
    NSPredicate *domainTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", domainRegex];
    return [domainTest evaluateWithObject:self] || [self isEqualToString:kAccountDomainId];
}

- (BOOL)validateUserName {
    NSString *nameRegex = @"^([a-z]|[A-Z]|[\u4e00-\u9fa5]|[\\s]|[0-9])*$";
    NSPredicate *nameTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",nameRegex];
    return [nameTest evaluateWithObject:self];
    
}

- (BOOL)validatePassword{
    if (self.length < 6 && self.length > 50) {
        return NO;
    }
    
    NSString *numberRegex = @"^.*[0-9]+.*$";
    NSPredicate *numberTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",numberRegex];
    BOOL isContainNumber =[numberTest evaluateWithObject:self];
    NSString *SmallLetter = @"^.*[a-z]+.*$";
    NSPredicate *SmallLetterTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",SmallLetter];
    BOOL isContainSmallLetter = [SmallLetterTest evaluateWithObject:self];
    NSString *CapitalLetterRegex = @"^.*[A-Z]+.*$";
    NSPredicate *CapitalLetterTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",CapitalLetterRegex];
    BOOL isContainCapitalLetter = [CapitalLetterTest evaluateWithObject:self];
    NSString *SymbolRegex = @"^.*[^a-zA-Z0-9]+.*$";
    NSPredicate *SymbolTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",SymbolRegex];
    BOOL isContainSymbol = [SymbolTest evaluateWithObject:self];
    
    BOOL isValidate = NO;
    int count = 0;
    if (isContainNumber) {
        count++;
    }
    if (isContainSmallLetter) {
        count++;
    }
    if (isContainCapitalLetter) {
        count++;
    }
    if (isContainSymbol) {
        count++;
    }
    if (count >= 2) {
        isValidate = YES;
    }
    return isValidate;
}


+(NSString*)generateShortID
{
    static char *charSet = "0123456789abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    static long autoId = 1;
    
    static NSString *idPrefix;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        
        NSInteger idLength = 5;
        unichar resultArray[idLength];
        for (int i = 0; i < idLength; i++) {
            resultArray[i] = charSet[arc4random()%72];
        }
        idPrefix = [[NSString stringWithCharacters:resultArray length:idLength] stringByAppendingString:@"-"] ;
    });
    NSString *autoIdStr;
    
    @synchronized([UIApplication sharedApplication]){
        autoIdStr = [NSString stringWithFormat:@"%ld", autoId++];
    }
    
    //时间戳转换为32进制
    NSInteger time = [[NSDate date] timeIntervalSince1970]*1000;
    NSString *temp = @"0123456789abcdefghijklmnopqrstuvwxyz";
    NSMutableString *duotricemary = @"".mutableCopy;
    NSInteger target = 32; //32进制
    while (time>=target) {
        [duotricemary insertString:[temp substringWithRange:NSMakeRange(time%target, 1)] atIndex:0];
        time = time/target;
    }
    [duotricemary insertString:[temp substringWithRange:NSMakeRange(time%target, 1)] atIndex:0];
    
    NSString *shortId = [idPrefix stringByAppendingString:[NSString stringWithFormat:@"%@-%@", duotricemary, autoIdStr]];
    
    return shortId;
}

//- (NSString *)appendingParams:(NSDictionary *)params
//{
//    if (!params || params.count<=0) {
//        return self;
//    }
//    
//    NSMutableArray* pairs = [NSMutableArray array];
//    for (NSString* key in params.keyEnumerator) {
//        NSString* value = [NSString stringWithFormat:@"%@", [params objectForKey:key]];
//        NSString* escaped_value = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, /* allocator */
//                                                                                                        (CFStringRef)value,
//                                                                                                        NULL, /* charactersToLeaveUnescaped */
//                                                                                                        (CFStringRef)@"!*'();:@&=+$,/?%#[]",kCFStringEncodingUTF8));
//        [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, escaped_value]];
//    }
//    NSString *query = [pairs componentsJoinedByString:@"&"];
//    return [NSString stringWithFormat:@"%@?%@", self, query];
//}

/**
 * 计算文字高度，可以处理计算带行间距的
 */
- (CGSize)boundingRectWithSize:(CGSize)size font:(UIFont*)font  lineSpacing:(CGFloat)lineSpacing
{
    NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:self];
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.lineSpacing = lineSpacing;
    [attributeString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, self.length)];
    [attributeString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, self.length)];
    NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading;
    CGRect rect = [attributeString boundingRectWithSize:size options:options context:nil];
    
    //    NSLog(@"size:%@", NSStringFromCGSize(rect.size));
    
    //文本的高度减去字体高度小于等于行间距，判断为当前只有1行
    if ((rect.size.height - font.lineHeight) <= paragraphStyle.lineSpacing) {
        if ([self containChinese]) {  //如果包含中文
            rect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height-paragraphStyle.lineSpacing);
        }
    }
    
    
    return CGSizeMake(ceilf(rect.size.width), ceil(rect.size.height));
}

/**
 *  计算最大行数文字高度,可以处理计算带行间距的
 */
- (CGFloat)boundingRectWithSize:(CGSize)size font:(UIFont*)font  lineSpacing:(CGFloat)lineSpacing maxLines:(NSInteger)maxLines{
    
    if (maxLines <= 0) {
        return 0;
    }
    
    CGFloat maxHeight = font.lineHeight * maxLines + lineSpacing * (maxLines - 1);
    
    CGSize orginalSize = [self boundingRectWithSize:size font:font lineSpacing:lineSpacing];
    
    if ( orginalSize.height >= maxHeight ) {
        return ceilf(maxHeight);
    }else{
        return ceilf(orginalSize.height);
    }
}

/**
 *  计算是否超过一行   用于给Label 赋值attribute text的时候 超过一行设置lineSpace
 */
- (BOOL)isMoreThanOneLineWithSize:(CGSize)size font:(UIFont *)font lineSpaceing:(CGFloat)lineSpacing{
    
    if ( [self boundingRectWithSize:size font:font lineSpacing:lineSpacing].height > font.lineHeight  ) {
        return YES;
    }else{
        return NO;
    }
}


//判断如果包含中文
- (BOOL)containChinese {
    for(int i=0; i< [self length];i++){
        int a = [self characterAtIndex:i];
        if( a >= 0x4e00 && a <= 0x9fff){
            return YES;
        }
    }
    return NO;
}

//判断是否由字母、数字或汉字组合名称
+(BOOL)validateName:(NSString *)name{
    NSString *nameRegex = @"^([a-z]|[A-Z]|[\u4e00-\u9fa5]|[\\s]|[0-9])*$";
    NSPredicate *nameTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",nameRegex];
    return [nameTest evaluateWithObject:name];
    
}

- (BOOL)containEmoji
{
    __block BOOL returnValue = NO;
    
    [self enumerateSubstringsInRange:NSMakeRange(0, [self length])
                               options:NSStringEnumerationByComposedCharacterSequences
                            usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
                                const unichar hs = [substring characterAtIndex:0];
                                if (0xd800 <= hs && hs <= 0xdbff) {
                                    if (substring.length > 1) {
                                        const unichar ls = [substring characterAtIndex:1];
                                        const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
                                        if (0x1d000 <= uc && uc <= 0x1f77f) {
                                            returnValue = YES;
                                        }
                                    }
                                } else if (substring.length > 1) {
                                    const unichar ls = [substring characterAtIndex:1];
                                    if (ls == 0x20e3) {
                                        returnValue = YES;
                                    }
                                } else {
                                    if (0x2100 <= hs && hs <= 0x27ff) {
                                        returnValue = YES;
                                    } else if (0x2B05 <= hs && hs <= 0x2b07) {
                                        returnValue = YES;
                                    } else if (0x2934 <= hs && hs <= 0x2935) {
                                        returnValue = YES;
                                    } else if (0x3297 <= hs && hs <= 0x3299) {
                                        returnValue = YES;
                                    } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) {
                                        returnValue = YES;
                                    }
                                }
                            }];
    
    return returnValue;
}

- (NSString *)phoneNumber{
    NSString *realPhone = self;
    //过滤掉特殊字符
    NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:@"- ()"];
    realPhone = [[realPhone componentsSeparatedByCharactersInSet:characterSet]componentsJoinedByString:@""];
    realPhone = [[realPhone componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] componentsJoinedByString:@""];
    return realPhone;
}

- (NSString *)reducedToWidth:(CGFloat)width withFont:(UIFont *)font {
    
    if ([self widthForFont:font] <= width)
        return self;
    
    NSMutableString *string = [NSMutableString string];
    for (NSInteger i = 0; i < self.length; i++) {
        [string appendString:[self substringWithRange:NSMakeRange(i, 1)]];
        if ([string widthForFont:font] > width) {
            if (string.length == 1)
                return string;
            [string deleteCharactersInRange:NSMakeRange(i, 1)];
            break;
        }
    }
    
    return string;
}

//- (CGSize)emojiStrSizeForFont:(UIFont *)font size:(CGSize)size
//{
//    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)one);
//    CGSize targetSize = CGSizeMake(100, CGFLOAT_MAX);
//    CGSize size1 = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, (CFIndex)[one length]), NULL, targetSize, NULL);
//    CFRelease(framesetter);
//}

+ (NSString *)formatFileSize:(NSInteger)fileSize
{
    NSString *formatedFileSize = nil;
    
    if (fileSize < 1024) {
        formatedFileSize = [NSString stringWithFormat:@"%lu Bytes",(long)fileSize];
    }else if (fileSize < 1024 * 1024){
        formatedFileSize = [NSString stringWithFormat:@"%.2f KB",fileSize / 1024.0];
    }else if (fileSize < 1024 * 1024 * 1024){
        formatedFileSize = [NSString stringWithFormat:@"%.2f MB",fileSize / (1024 * 1024.0)];
    }else{
        formatedFileSize = [NSString stringWithFormat:@"%.2f GB",fileSize / (1024 * 1024 * 1024.0)];
    }
    
    return formatedFileSize;
}

- (NSMutableArray *)locationsOfText:(NSString *)text {
    if (isNullStr(text)) {
        return [NSMutableArray array];
    }
    
    NSMutableArray *locations = [NSMutableArray array];
    NSRange range = NSMakeRange(0, 0);
    while (range.location != NSNotFound) {
        NSRange searchRange = NSMakeRange(range.location + range.length, self.length - range.location - range.length);
        range = [self rangeOfString:text options:NSCaseInsensitiveSearch range:searchRange];
        if (range.location != NSNotFound) {
            [locations addObject:@(range.location)];
        }
    }
    return locations;
    
}

- (BOOL)isQingTuiURL {
    NSString *urlRegex = @"^https://(.*\\.)?qingtui\\.im(/.*)?";
    NSPredicate *urlTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@",urlRegex];
    return [urlTest evaluateWithObject:self];
}

- (BOOL)supportPreview {
    NSString *extension = self.pathExtension.lowercaseString;
    
    NSArray *supportedType = @[@"txt",@"doc",@"docx",@"xls",@"xlsx",@"ppt",@"pptx",@"pdf",@"rtf",@"key",@"numbers",@"pages",@"png",@"jpg",@"jpeg"];
    
    if ([supportedType containsObject:extension]) {
        return YES;
    }else{
        return NO;
    }
}

- (NSString *)jsCallBackString {
    if (isNullStr(self)) {
        return self;
    };
    
    return [[self stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]
            stringByReplacingOccurrencesOfString:@"'" withString:@"\\u0027"];
}

- (NSString *)sqliteEscapeString {
//    return self;
    NSString *string = [self stringByReplacingOccurrencesOfString:@"/" withString:@"//"];
    string = [string stringByReplacingOccurrencesOfString:@"\"" withString:@"/\""];
    string = [string stringByReplacingOccurrencesOfString:@"[" withString:@"/["];
    string = [string stringByReplacingOccurrencesOfString:@"]" withString:@"/]"];
    string = [string stringByReplacingOccurrencesOfString:@"%" withString:@"/%"];
    string = [string stringByReplacingOccurrencesOfString:@"&" withString:@"/&"];
    string = [string stringByReplacingOccurrencesOfString:@"_" withString:@"/_"];
    string = [string stringByReplacingOccurrencesOfString:@"(" withString:@"/("];
    string = [string stringByReplacingOccurrencesOfString:@")" withString:@"/)"];
    return string;
}

@end
